library(knitr)
opts_chunk$set(eval=TRUE, include=TRUE, cache=FALSE, cache.path='./__cache__/',
bootstrap.thumbnail.size= 'col-md-12', bootstrap.thumbnail = TRUE, bootstrap.show.code= FALSE,
fig.path='.', dev=c('png','pdf','svg','cairo_ps'), fig.width=8, fig.height=4, dpi=300)
knit_hooks$set(embed_fonts = function(before, options, envir) {
if ((!before) & (length(options['label'])>0)) {
old_path <- paste0(options['fig.path'], options['label'], '.pdf')
new_path <- paste0(options['fig.path'], options['label'], '-1.pdf')
if (file.exists(old_path)) {
embed_fonts(old_path, outfile = new_path)
}
NULL
}
})
# library(rmarkdown)
# render('political_affinity/pol_affn.Rmd', 'all', knit_root_dir='..')
library(data.table)
library(ggplot2)
library(ggridges)
library(ggrepel)
library(scales)
library(stats)
library(Hmisc)
# library(RColorBrewer)
library(car)
library(stargazer)
# library(doParallel)
# registerDoParallel(cores = 7)
library(arm)
library(glmnet)
library(pROC)
vars <- c("urls", "urls_panel", "urls_exp", "friendships", "panel")
if (length(setdiff(vars, ls(all.names = T)))>0) {
source("util/load_exp_data.R", chdir = T)
}
pol_act_l <- c("extreme left", "left", "center", "right", "extreme right",
"apolitical", "bot", "superconsumer", "supersharer")
# political exposure per user and site
user_site_exp <- urls_exp[domain_color_num>4,.(n_exp=.N), by=.(panel_uid, website)]
user_site_exp <- user_site_exp[, `:=`(
pct_site_exp=n_exp/sum(n_exp),
total_pol_exp=sum(n_exp)),
by=.(panel_uid)]
user_site_exp <- merge(x=user_site_exp,
y=panel[!is.na(party) & party %in% c("Republican", "Democrat") & is_outlier==F,
.(user_id, party)],
by.x = "panel_uid", by.y = "user_id", all.x = T)
# site_align <- fread("political_affinity/site_align.tsv")
align_exp <- user_site_exp[!is.na(party) & total_pol_exp>=100 & pct_site_exp>0.01,]
align_exp <- align_exp[, `:=`(n_uniq_users=.N), by=.(website)]
nd <- length(unique(align_exp[n_uniq_users>30 & party=="Democrat"]$panel_uid))
nr <- length(unique(align_exp[n_uniq_users>30 & party=="Republican"]$panel_uid))
wd <- 0.5*(nd+nr)/nd
wr <- 0.5*(nd+nr)/nr
site_align_rep <- align_exp[n_uniq_users>30,
.(n=.N,
n_rep=sum(party=="Republican"),
n_dem=sum(party=="Democrat")), by=.(website)]
site_align_rep <- site_align_rep[,`:=`(
#align_raw = 2*n_rep/n-1,
align = 2*wr*n_rep/(wd*n_dem+wr*n_rep)-1
)]
site_align <- site_align_rep[,.(website, align)]
# Using Facebook's top 500 sites from Science paper
fb_domain_align <- fread('restricted_data/fb_top500_domain_affl.csv', showProgress = F,
select = c("domain", "avg_align"))
fb_domain_align <- unique(fb_domain_align, by=c("domain"))
fb_domain_align <- merge(x=fb_domain_align, y=site_align, by.x = "domain",
by.y = "website", all.x = T)[order(avg_align)]
print(sprintf("%d/%d sites overlaped with Bakshy et al.'s list",
nrow(fb_domain_align[!is.na(align)]), nrow(fb_domain_align) ))
[1] "109/495 sites overlaped with Bakshy et al.'s list"
print(cor.test(fb_domain_align[!is.na(align)]$avg_align,
fb_domain_align[!is.na(align)]$align,
method = "pearson", conf.level = 0.95))
Pearson's product-moment correlation
data: fb_domain_align[!is.na(align)]$avg_align and fb_domain_align[!is.na(align)]$align
t = 22.578, df = 107, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.8697598 0.9369938
sample estimates:
cor
0.9091256
ggplot(data = fb_domain_align[!is.na(align),],
aes(x=avg_align, y=align )) +
geom_point() +
scale_x_continuous(expand=c(0,0), limits=c(-1,1)) +
scale_y_continuous(expand=c(0,0), limits=c(-1,1)) +
geom_smooth(data=fb_domain_align[!is.na(align),], method='lm',formula=y~x, fullrange=T) +
geom_abline(slope = 1, intercept = 0) +
geom_text_repel(aes(label=domain), size=1) +
labs(y="Site Alignment", x="Alignment (Bakshy et al.)") +
theme(axis.line.x=element_blank())

budak <- data.table(
website=c(
"dailykos.com", "nytimes.com", "huffingtonpost.com", "latimes.com",
"washingtonpost.com", "bbcnews.com", "cnn.com", "yahoo.com", "reuters.com",
"nbcnews.com", "chicagotribune.com", "usatoday.com", "wsj.com",
"foxnews.com", "breitbart.com"),
slant=c(-0.24, -0.054, -0.05, -0.04,
-0.01, -0.01, -0.005, -0.005, 0,
0.005, 0.01, 0.11, 0.06,
0.11, 0.17))
budak <- merge(x=budak, y=site_align, by = "website", all.x = T)[order(slant)]
budak_m <- budak[!is.na(align),]
print(sprintf("%d/%d sites overlaped with Budak et al.'s list",
nrow(budak_m), nrow(budak) ))
[1] "14/15 sites overlaped with Budak et al.'s list"
print(cor.test(budak_m$slant,budak_m$align, method = "pearson", conf.level = 0.95))
Pearson's product-moment correlation
data: budak_m$slant and budak_m$align
t = 6.8173, df = 12, p-value = 1.857e-05
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.6848938 0.9654257
sample estimates:
cor
0.8915077
print(budak_m[order(slant),.(website, slant, align)])
website slant align
1: dailykos.com -0.240 -0.606063164
2: nytimes.com -0.054 -0.155912285
3: huffingtonpost.com -0.050 -0.337856555
4: latimes.com -0.040 -0.258046270
5: washingtonpost.com -0.010 -0.132981727
6: cnn.com -0.005 -0.071515112
7: yahoo.com -0.005 0.005735093
8: reuters.com 0.000 -0.083953557
9: nbcnews.com 0.005 -0.089164047
10: chicagotribune.com 0.010 -0.127352043
11: wsj.com 0.060 0.079104664
12: foxnews.com 0.110 0.685500953
13: usatoday.com 0.110 0.093322588
14: breitbart.com 0.170 0.603952822
user_align_sites <- merge(x=user_site_exp,
y=site_align[,.(website, align)],
by = "website")
user_align <- user_align_sites[,.(pol_align=weighted.mean(align, n_exp)),
by=.(panel_uid)]
imp_data <- merge(x=panel[,.(user_id, perc_obama, party, is_outlier, pol_affl)], y=user_align, by.x = "user_id", by.y = "panel_uid", all.x = T)
imp_data <- imp_data[, party_dv:=factor(party, c("Democrat", "Republican"))]
imp_data <- imp_data[, party:=NULL]
imp_no_na <- imp_data[!is.na(party_dv) & is_outlier==F,]
# train on registered voters, predict continous score for everyone
f_rest <- ~ perc_obama + pol_align
m1 <- cv.glmnet(as.matrix(model.matrix(f_rest, imp_no_na[!is.na(pol_align)])),
imp_no_na[!is.na(pol_align)]$party_dv, family="binomial", alpha = 0,
# original dataset had slightly different mean so offseting now
offset = rep(-0.17, nrow(imp_no_na[!is.na(pol_align)]))
)
imp_data <- imp_data[!is.na(pol_align), party_score:=
as.vector(predict(m1, newx = as.matrix(model.matrix(f_rest, imp_data[!is.na(pol_align)])),
s = "lambda.min", type = "response", newoffset = 0))]
# train a second model based on just the perc_obama for cases where pol_align is NA
m2 <- cv.glmnet(as.matrix(model.matrix(~ perc_obama, imp_no_na)),
imp_no_na$party_dv, family="binomial", alpha = 0, offset = rep(-0.38, nrow(imp_no_na)))
imp_data <- imp_data[is.na(pol_align), party_score:=
as.vector(predict(m2, newx = as.matrix(model.matrix(~ perc_obama, imp_data[is.na(pol_align)])),
s = "lambda.1se", type = "response", newoffset = 0))]
imp_data <- imp_data[, pol_affl_rep:=2*party_score-1]
print(sprintf("99%% of reproduced affiliation scores are less than this much off: %2.3f",
quantile(abs(imp_data$pol_affl-imp_data$pol_affl_rep), 0.99)))
[1] "99% of reproduced affiliation scores are less than this much off: 0.008"
print(auc(imp_data[!is.na(party_dv),]$party_dv, imp_data[!is.na(party_dv),]$party_score)) # 0.8074
Area under the curve: 0.8073
plot_df <- panel[is_compromised==F & is_bot==F & pol_affl_act!="apolitical",]
lvls_rev <- function(f) factor(f, rev(levels(f)))
plot_lbls <- plot_df[,.(
lbl=sprintf("N=%d, %2.0f%%", .N, 100*sum(n_fn_exp<1)/.N), exp_rate=median(exp_rate[n_fn_exp>0])),
by=pol_affl_act]
ggplot(plot_df[n_fn_exp>0], aes(x=exp_rate, y=lvls_rev(pol_affl_act) )) +
geom_density_ridges_gradient(
aes(fill = ..x..), scale = 2, size = 0.3
) +
scale_fill_gradientn(
colours = c("#0D0887FF", "#CC4678FF", "#F0F921FF"),
guide = "none"
) +
# geom_text(data = plot_lbls, aes(label=nz_pct), size=4, colour="black", vjust = -2, nudge_x = -0.3, hjust = 0.5) +
geom_text(data = plot_lbls, aes(label=lbl, x=0.00015), size=4, colour="black", vjust = -3.5, hjust = 0) +
scale_x_log10(labels=percent, breaks = c(0.001, 0.01, 0.1), limits = c(0.0001, 0.6), expand = c(0, 0) ) +
scale_y_discrete(expand = c(0.04, 0)) +
annotation_logticks(sides = "b") +
labs(x="Fraction of fake news", y = NULL)
Picking joint bandwidth of 0.162

LS0tCnRpdGxlOiAiQ2FsY3VsYXRlIHBvbGl0aWNhbCBhZmZpbml0eSBzY29yZXMiCmF1dGhvcjogIk5pciBHcmluYmVyZyIKZGF0ZTogIjEyLzMxLzIwMTgiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9wOiB5ZXMKICBtZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3IgZ2xvYmFsX3NldHRpbmdzfQpsaWJyYXJ5KGtuaXRyKQpvcHRzX2NodW5rJHNldChldmFsPVRSVUUsIGluY2x1ZGU9VFJVRSwgY2FjaGU9RkFMU0UsIGNhY2hlLnBhdGg9Jy4vX19jYWNoZV9fLycsCiAgICAgICAgICAgICAgIGJvb3RzdHJhcC50aHVtYm5haWwuc2l6ZT0gJ2NvbC1tZC0xMicsIGJvb3RzdHJhcC50aHVtYm5haWwgPSBUUlVFLCBib290c3RyYXAuc2hvdy5jb2RlPSBGQUxTRSwgCiAgICAgICAgICAgICAgIGZpZy5wYXRoPScuJywgZGV2PWMoJ3BuZycsJ3BkZicsJ3N2ZycsJ2NhaXJvX3BzJyksIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTQsIGRwaT0zMDApCgprbml0X2hvb2tzJHNldChlbWJlZF9mb250cyA9IGZ1bmN0aW9uKGJlZm9yZSwgb3B0aW9ucywgZW52aXIpIHsKICBpZiAoKCFiZWZvcmUpICYgKGxlbmd0aChvcHRpb25zWydsYWJlbCddKT4wKSkgewogICAgb2xkX3BhdGggPC0gcGFzdGUwKG9wdGlvbnNbJ2ZpZy5wYXRoJ10sIG9wdGlvbnNbJ2xhYmVsJ10sICcucGRmJykKICAgIG5ld19wYXRoIDwtIHBhc3RlMChvcHRpb25zWydmaWcucGF0aCddLCBvcHRpb25zWydsYWJlbCddLCAnLTEucGRmJykKICAgIGlmIChmaWxlLmV4aXN0cyhvbGRfcGF0aCkpIHsKICAgICAgICBlbWJlZF9mb250cyhvbGRfcGF0aCwgb3V0ZmlsZSA9IG5ld19wYXRoKQogICAgfQogICAgTlVMTAogIH0KfSkKIyBsaWJyYXJ5KHJtYXJrZG93bikKIyByZW5kZXIoJ3BvbGl0aWNhbF9hZmZpbml0eS9wb2xfYWZmbi5SbWQnLCAnYWxsJywga25pdF9yb290X2Rpcj0nLi4nKQpgYGAKCmBgYHtyIGltcG9ydHMsIGV2YWw9VFJVRSwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJywgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHN0YXRzKQpsaWJyYXJ5KEhtaXNjKQojIGxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNhcikKbGlicmFyeShzdGFyZ2F6ZXIpCiMgbGlicmFyeShkb1BhcmFsbGVsKQojIHJlZ2lzdGVyRG9QYXJhbGxlbChjb3JlcyA9IDcpCmxpYnJhcnkoYXJtKQpsaWJyYXJ5KGdsbW5ldCkKbGlicmFyeShwUk9DKQpgYGAKCmBgYHtyIGxvYWRfZXhwX2RhdGF9CnZhcnMgPC0gYygidXJscyIsICJ1cmxzX3BhbmVsIiwgInVybHNfZXhwIiwgImZyaWVuZHNoaXBzIiwgInBhbmVsIikKaWYgKGxlbmd0aChzZXRkaWZmKHZhcnMsIGxzKGFsbC5uYW1lcyA9IFQpKSk+MCkgewogIHNvdXJjZSgidXRpbC9sb2FkX2V4cF9kYXRhLlIiLCBjaGRpciA9IFQpCn0KcG9sX2FjdF9sIDwtIGMoImV4dHJlbWUgbGVmdCIsICJsZWZ0IiwgImNlbnRlciIsICJyaWdodCIsICJleHRyZW1lIHJpZ2h0IiwgCiAgICAgICAgICAgICAgICJhcG9saXRpY2FsIiwgImJvdCIsICJzdXBlcmNvbnN1bWVyIiwgInN1cGVyc2hhcmVyIikKIyBwb2xpdGljYWwgZXhwb3N1cmUgcGVyIHVzZXIgYW5kIHNpdGUKdXNlcl9zaXRlX2V4cCA8LSB1cmxzX2V4cFtkb21haW5fY29sb3JfbnVtPjQsLihuX2V4cD0uTiksIGJ5PS4ocGFuZWxfdWlkLCB3ZWJzaXRlKV0KdXNlcl9zaXRlX2V4cCA8LSB1c2VyX3NpdGVfZXhwWywgYDo9YCgKICBwY3Rfc2l0ZV9leHA9bl9leHAvc3VtKG5fZXhwKSwKICB0b3RhbF9wb2xfZXhwPXN1bShuX2V4cCkpLCAKICBieT0uKHBhbmVsX3VpZCldCnVzZXJfc2l0ZV9leHAgPC0gbWVyZ2UoeD11c2VyX3NpdGVfZXhwLCAKICAgICAgICAgICAgICAgICAgICAgICB5PXBhbmVsWyFpcy5uYShwYXJ0eSkgJiBwYXJ0eSAlaW4lIGMoIlJlcHVibGljYW4iLCAiRGVtb2NyYXQiKSAmIGlzX291dGxpZXI9PUYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuKHVzZXJfaWQsIHBhcnR5KV0sCiAgICAgICAgICAgICAgICAgICAgICAgYnkueCA9ICJwYW5lbF91aWQiLCBieS55ID0gInVzZXJfaWQiLCBhbGwueCA9IFQpCmBgYAoKYGBge3IgY29tcHV0ZV9zaXRlX2FsaWdufQojIHNpdGVfYWxpZ24gPC0gZnJlYWQoInBvbGl0aWNhbF9hZmZpbml0eS9zaXRlX2FsaWduLnRzdiIpCmFsaWduX2V4cCA8LSB1c2VyX3NpdGVfZXhwWyFpcy5uYShwYXJ0eSkgJiB0b3RhbF9wb2xfZXhwPj0xMDAgJiBwY3Rfc2l0ZV9leHA+MC4wMSxdCmFsaWduX2V4cCA8LSBhbGlnbl9leHBbLCBgOj1gKG5fdW5pcV91c2Vycz0uTiksIGJ5PS4od2Vic2l0ZSldCm5kIDwtIGxlbmd0aCh1bmlxdWUoYWxpZ25fZXhwW25fdW5pcV91c2Vycz4zMCAmIHBhcnR5PT0iRGVtb2NyYXQiXSRwYW5lbF91aWQpKQpuciA8LSBsZW5ndGgodW5pcXVlKGFsaWduX2V4cFtuX3VuaXFfdXNlcnM+MzAgJiBwYXJ0eT09IlJlcHVibGljYW4iXSRwYW5lbF91aWQpKQp3ZCA8LSAwLjUqKG5kK25yKS9uZAp3ciA8LSAwLjUqKG5kK25yKS9ucgpzaXRlX2FsaWduX3JlcCA8LSBhbGlnbl9leHBbbl91bmlxX3VzZXJzPjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLihuPS5OLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3JlcD1zdW0ocGFydHk9PSJSZXB1YmxpY2FuIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5fZGVtPXN1bShwYXJ0eT09IkRlbW9jcmF0IikpLCBieT0uKHdlYnNpdGUpXQpzaXRlX2FsaWduX3JlcCA8LSBzaXRlX2FsaWduX3JlcFssYDo9YCgKICAjYWxpZ25fcmF3ID0gMipuX3JlcC9uLTEsCiAgYWxpZ24gICAgID0gMip3cipuX3JlcC8od2Qqbl9kZW0rd3Iqbl9yZXApLTEKKV0Kc2l0ZV9hbGlnbiA8LSBzaXRlX2FsaWduX3JlcFssLih3ZWJzaXRlLCBhbGlnbildCmBgYAoKYGBge3IgY29tcGFyZV93aXRoX2Jha3NoeV9ldGFsfQojIFVzaW5nIEZhY2Vib29rJ3MgdG9wIDUwMCBzaXRlcyBmcm9tIFNjaWVuY2UgcGFwZXIKZmJfZG9tYWluX2FsaWduIDwtIGZyZWFkKCdyZXN0cmljdGVkX2RhdGEvZmJfdG9wNTAwX2RvbWFpbl9hZmZsLmNzdicsIHNob3dQcm9ncmVzcyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ID0gYygiZG9tYWluIiwgImF2Z19hbGlnbiIpKQpmYl9kb21haW5fYWxpZ24gPC0gdW5pcXVlKGZiX2RvbWFpbl9hbGlnbiwgYnk9YygiZG9tYWluIikpCmZiX2RvbWFpbl9hbGlnbiA8LSBtZXJnZSh4PWZiX2RvbWFpbl9hbGlnbiwgeT1zaXRlX2FsaWduLCBieS54ID0gImRvbWFpbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgYnkueSA9ICJ3ZWJzaXRlIiwgYWxsLnggPSBUKVtvcmRlcihhdmdfYWxpZ24pXQpwcmludChzcHJpbnRmKCIlZC8lZCBzaXRlcyBvdmVybGFwZWQgd2l0aCBCYWtzaHkgZXQgYWwuJ3MgbGlzdCIsIAogICAgICAgICAgICAgIG5yb3coZmJfZG9tYWluX2FsaWduWyFpcy5uYShhbGlnbildKSwgbnJvdyhmYl9kb21haW5fYWxpZ24pICkpIApwcmludChjb3IudGVzdChmYl9kb21haW5fYWxpZ25bIWlzLm5hKGFsaWduKV0kYXZnX2FsaWduLCAKICAgICAgICAgICAgICAgZmJfZG9tYWluX2FsaWduWyFpcy5uYShhbGlnbildJGFsaWduLCAKICAgICAgICAgICAgICAgbWV0aG9kID0gInBlYXJzb24iLCBjb25mLmxldmVsID0gMC45NSkpCgpnZ3Bsb3QoZGF0YSA9IGZiX2RvbWFpbl9hbGlnblshaXMubmEoYWxpZ24pLF0sIAogICAgICAgICAgICBhZXMoeD1hdmdfYWxpZ24sIHk9YWxpZ24gKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQ9YygwLDApLCBsaW1pdHM9YygtMSwxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQ9YygwLDApLCBsaW1pdHM9YygtMSwxKSkgKwogIGdlb21fc21vb3RoKGRhdGE9ZmJfZG9tYWluX2FsaWduWyFpcy5uYShhbGlnbiksXSwgbWV0aG9kPSdsbScsZm9ybXVsYT15fngsIGZ1bGxyYW5nZT1UKSArIAogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKyAKICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWRvbWFpbiksIHNpemU9MSkgKwogIGxhYnMoeT0iU2l0ZSBBbGlnbm1lbnQiLCB4PSJBbGlnbm1lbnQgKEJha3NoeSBldCBhbC4pIikgKyAKICB0aGVtZShheGlzLmxpbmUueD1lbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3IgY29tcGFyZV93aXRoX2J1ZGFrX2V0YWx9CmJ1ZGFrIDwtIGRhdGEudGFibGUoCiAgd2Vic2l0ZT1jKAogICAgImRhaWx5a29zLmNvbSIsICJueXRpbWVzLmNvbSIsICJodWZmaW5ndG9ucG9zdC5jb20iLCAibGF0aW1lcy5jb20iLCAKICAgICJ3YXNoaW5ndG9ucG9zdC5jb20iLCAiYmJjbmV3cy5jb20iLCAiY25uLmNvbSIsICJ5YWhvby5jb20iLCAicmV1dGVycy5jb20iLAogICAgIm5iY25ld3MuY29tIiwgImNoaWNhZ290cmlidW5lLmNvbSIsICJ1c2F0b2RheS5jb20iLCAid3NqLmNvbSIsIAogICAgImZveG5ld3MuY29tIiwgImJyZWl0YmFydC5jb20iKSwgCiAgc2xhbnQ9YygtMC4yNCwgLTAuMDU0LCAtMC4wNSwgIC0wLjA0LCAKICAgICAgICAgIC0wLjAxLCAtMC4wMSwgIC0wLjAwNSwgLTAuMDA1LCAwLCAKICAgICAgICAgIDAuMDA1LCAgMC4wMSwgICAwLjExLCAgIDAuMDYsICAKICAgICAgICAgIDAuMTEsICAgMC4xNykpCmJ1ZGFrIDwtIG1lcmdlKHg9YnVkYWssIHk9c2l0ZV9hbGlnbiwgYnkgPSAid2Vic2l0ZSIsIGFsbC54ID0gVClbb3JkZXIoc2xhbnQpXQpidWRha19tIDwtIGJ1ZGFrWyFpcy5uYShhbGlnbiksXQpwcmludChzcHJpbnRmKCIlZC8lZCBzaXRlcyBvdmVybGFwZWQgd2l0aCBCdWRhayBldCBhbC4ncyBsaXN0IiwgCiAgICAgICAgICAgICAgbnJvdyhidWRha19tKSwgbnJvdyhidWRhaykgKSkgCnByaW50KGNvci50ZXN0KGJ1ZGFrX20kc2xhbnQsYnVkYWtfbSRhbGlnbiwgbWV0aG9kID0gInBlYXJzb24iLCBjb25mLmxldmVsID0gMC45NSkpCnByaW50KGJ1ZGFrX21bb3JkZXIoc2xhbnQpLC4od2Vic2l0ZSwgc2xhbnQsIGFsaWduKV0pCmBgYAoKYGBge3IgY29tcHV0ZV91c2VyX2FsaWduX3Njb3Jlc30KdXNlcl9hbGlnbl9zaXRlcyA8LSBtZXJnZSh4PXVzZXJfc2l0ZV9leHAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1zaXRlX2FsaWduWywuKHdlYnNpdGUsIGFsaWduKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAid2Vic2l0ZSIpCnVzZXJfYWxpZ24gPC0gdXNlcl9hbGlnbl9zaXRlc1ssLihwb2xfYWxpZ249d2VpZ2h0ZWQubWVhbihhbGlnbiwgbl9leHApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieT0uKHBhbmVsX3VpZCldCmBgYAoKYGBge3IgY29tcHV0ZV9wb2xfYWZmbH0KaW1wX2RhdGEgPC0gbWVyZ2UoeD1wYW5lbFssLih1c2VyX2lkLCBwZXJjX29iYW1hLCBwYXJ0eSwgaXNfb3V0bGllciwgcG9sX2FmZmwpXSwgeT11c2VyX2FsaWduLCBieS54ID0gInVzZXJfaWQiLCBieS55ID0gInBhbmVsX3VpZCIsIGFsbC54ID0gVCkKaW1wX2RhdGEgPC0gaW1wX2RhdGFbLCBwYXJ0eV9kdjo9ZmFjdG9yKHBhcnR5LCBjKCJEZW1vY3JhdCIsICJSZXB1YmxpY2FuIikpXQppbXBfZGF0YSA8LSBpbXBfZGF0YVssIHBhcnR5Oj1OVUxMXQppbXBfbm9fbmEgPC0gaW1wX2RhdGFbIWlzLm5hKHBhcnR5X2R2KSAmIGlzX291dGxpZXI9PUYsXQoKIyB0cmFpbiBvbiByZWdpc3RlcmVkIHZvdGVycywgcHJlZGljdCBjb250aW5vdXMgc2NvcmUgZm9yIGV2ZXJ5b25lCmZfcmVzdCA8LSB+IHBlcmNfb2JhbWEgKyBwb2xfYWxpZ24gCm0xIDwtIGN2LmdsbW5ldChhcy5tYXRyaXgobW9kZWwubWF0cml4KGZfcmVzdCwgaW1wX25vX25hWyFpcy5uYShwb2xfYWxpZ24pXSkpLCAKICAgICAgICAgICAgICAgIGltcF9ub19uYVshaXMubmEocG9sX2FsaWduKV0kcGFydHlfZHYsIGZhbWlseT0iYmlub21pYWwiLCBhbHBoYSA9IDAsCiAgICAgICAgICAgICAgICAjIG9yaWdpbmFsIGRhdGFzZXQgaGFkIHNsaWdodGx5IGRpZmZlcmVudCBtZWFuIHNvIG9mZnNldGluZyBub3cKICAgICAgICAgICAgICAgIG9mZnNldCA9IHJlcCgtMC4xNywgbnJvdyhpbXBfbm9fbmFbIWlzLm5hKHBvbF9hbGlnbildKSkgCiAgICAgICAgICAgICAgICApCmltcF9kYXRhIDwtIGltcF9kYXRhWyFpcy5uYShwb2xfYWxpZ24pLCBwYXJ0eV9zY29yZTo9CiAgICAgICAgICAgICAgICAgICAgICAgYXMudmVjdG9yKHByZWRpY3QobTEsIG5ld3ggPSBhcy5tYXRyaXgobW9kZWwubWF0cml4KGZfcmVzdCwgaW1wX2RhdGFbIWlzLm5hKHBvbF9hbGlnbildKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMgPSAibGFtYmRhLm1pbiIsIHR5cGUgPSAicmVzcG9uc2UiLCBuZXdvZmZzZXQgPSAwKSldCgojIHRyYWluIGEgc2Vjb25kIG1vZGVsIGJhc2VkIG9uIGp1c3QgdGhlIHBlcmNfb2JhbWEgZm9yIGNhc2VzIHdoZXJlIHBvbF9hbGlnbiBpcyBOQQptMiA8LSBjdi5nbG1uZXQoYXMubWF0cml4KG1vZGVsLm1hdHJpeCh+IHBlcmNfb2JhbWEsIGltcF9ub19uYSkpLCAKICAgICAgICAgICAgICAgIGltcF9ub19uYSRwYXJ0eV9kdiwgZmFtaWx5PSJiaW5vbWlhbCIsIGFscGhhID0gMCwgb2Zmc2V0ID0gcmVwKC0wLjM4LCBucm93KGltcF9ub19uYSkpKQppbXBfZGF0YSA8LSBpbXBfZGF0YVtpcy5uYShwb2xfYWxpZ24pLCBwYXJ0eV9zY29yZTo9CiAgICAgICAgICAgICAgICAgICAgICAgYXMudmVjdG9yKHByZWRpY3QobTIsIG5ld3ggPSBhcy5tYXRyaXgobW9kZWwubWF0cml4KH4gcGVyY19vYmFtYSwgaW1wX2RhdGFbaXMubmEocG9sX2FsaWduKV0pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcyA9ICJsYW1iZGEuMXNlIiwgdHlwZSA9ICJyZXNwb25zZSIsIG5ld29mZnNldCA9IDApKV0KaW1wX2RhdGEgPC0gaW1wX2RhdGFbLCBwb2xfYWZmbF9yZXA6PTIqcGFydHlfc2NvcmUtMV0KCnByaW50KHNwcmludGYoIjk5JSUgb2YgcmVwcm9kdWNlZCBhZmZpbGlhdGlvbiBzY29yZXMgYXJlIGxlc3MgdGhhbiB0aGlzIG11Y2ggb2ZmOiAlMi4zZiIsIAogICAgICAgICAgICAgIHF1YW50aWxlKGFicyhpbXBfZGF0YSRwb2xfYWZmbC1pbXBfZGF0YSRwb2xfYWZmbF9yZXApLCAwLjk5KSkpCnByaW50KGF1YyhpbXBfZGF0YVshaXMubmEocGFydHlfZHYpLF0kcGFydHlfZHYsIGltcF9kYXRhWyFpcy5uYShwYXJ0eV9kdiksXSRwYXJ0eV9zY29yZSkpICMgMC44MDc0CmBgYAoKYGBge3IgZm5fZXhwX2Rpc3RfYnlfcG9sX2FmZmwsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTh9CnBsb3RfZGYgPC0gcGFuZWxbaXNfY29tcHJvbWlzZWQ9PUYgJiBpc19ib3Q9PUYgJiBwb2xfYWZmbF9hY3QhPSJhcG9saXRpY2FsIixdCmx2bHNfcmV2IDwtIGZ1bmN0aW9uKGYpIGZhY3RvcihmLCByZXYobGV2ZWxzKGYpKSkKcGxvdF9sYmxzIDwtIHBsb3RfZGZbLC4oCiAgICAgICAgICAgICAgICAgICAgbGJsPXNwcmludGYoIk49JWQsICUyLjBmJSUiLCAuTiwgMTAwKnN1bShuX2ZuX2V4cDwxKS8uTiksIGV4cF9yYXRlPW1lZGlhbihleHBfcmF0ZVtuX2ZuX2V4cD4wXSkpLCAKICAgICAgICAgICAgICAgICAgICBieT1wb2xfYWZmbF9hY3RdCmdncGxvdChwbG90X2RmW25fZm5fZXhwPjBdLCBhZXMoeD1leHBfcmF0ZSwgeT1sdmxzX3Jldihwb2xfYWZmbF9hY3QpICkpICsgCiAgZ2VvbV9kZW5zaXR5X3JpZGdlc19ncmFkaWVudCgKICAgIGFlcyhmaWxsID0gLi54Li4pLCBzY2FsZSA9IDIsIHNpemUgPSAwLjMKICApICsKICBzY2FsZV9maWxsX2dyYWRpZW50bigKICAgIGNvbG91cnMgPSBjKCIjMEQwODg3RkYiLCAiI0NDNDY3OEZGIiwgIiNGMEY5MjFGRiIpLAogICAgZ3VpZGUgPSAibm9uZSIKICApICsKICAjIGdlb21fdGV4dChkYXRhID0gcGxvdF9sYmxzLCBhZXMobGFiZWw9bnpfcGN0KSwgc2l6ZT00LCBjb2xvdXI9ImJsYWNrIiwgdmp1c3QgPSAtMiwgbnVkZ2VfeCA9IC0wLjMsIGhqdXN0ID0gMC41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBwbG90X2xibHMsIGFlcyhsYWJlbD1sYmwsIHg9MC4wMDAxNSksIHNpemU9NCwgY29sb3VyPSJibGFjayIsIHZqdXN0ID0gLTMuNSwgaGp1c3QgPSAwKSArCiAgc2NhbGVfeF9sb2cxMChsYWJlbHM9cGVyY2VudCwgYnJlYWtzID0gYygwLjAwMSwgMC4wMSwgMC4xKSwgbGltaXRzID0gYygwLjAwMDEsIDAuNiksIGV4cGFuZCA9IGMoMCwgMCkgKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBjKDAuMDQsIDApKSArCiAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzaWRlcyA9ICJiIikgKwogIGxhYnMoeD0iRnJhY3Rpb24gb2YgZmFrZSBuZXdzIiwgeSA9IE5VTEwpCmBgYA==